﻿/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#include "pch.h"
#include <App.xaml.h>
#include <page.xaml.h>
#include <error.xaml.h>
#include <windows.ui.xaml.media.dxinterop.h>

using namespace Platform;

using namespace Windows::Foundation;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Core;

using namespace baja;
using namespace baja::app;
using namespace baja::math;
using namespace std;

using namespace journal;

App::App()
{
    InitializeComponent();

    Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
    UnhandledException += ref new UnhandledExceptionEventHandler(this, &App::OnUnhandledException);
}

void App::OnLaunched(LaunchActivatedEventArgs^ pArgs)
{
    // connect the shell to the app
    try
    {
        g::checkIsValid(constants::general::useWARP());
    }
    catch (baja::win32_error e)
    {
        if (e.hr() == 0x887A0004) // DXGI_ERROR_UNSUPPORTED
        {
            error^ p = ref new error();
            Window::Current->Content = p;
            return;
        }
    }

    page^ p = ref new page();
    
    b::services::set<journal_app>(p->uiService());

    Microsoft::WRL::ComPtr<IInspectable> panelInspectable = reinterpret_cast<IInspectable*>(p);
    Microsoft::WRL::ComPtr<ISwapChainBackgroundPanelNative> panelNative;
    panelInspectable.As(&panelNative);
    
    std::shared_ptr<igraphics_factory> graphicsFactory = createGraphicsFactory(
        point2d(
            static_cast<float32>(Window::Current->CoreWindow->Bounds.Width), 
            static_cast<float32>(Window::Current->CoreWindow->Bounds.Height)
            ),
        panelNative.Get()
        );

    b::stopwatch sw;
    _shell = createShell(
        Application::Current, 
        Window::Current->CoreWindow,
        p
        );

    _app = createApp(
        _shell, 
        graphicsFactory
        );

    b::wchar* stateString = L"<none>";
    switch (pArgs->PreviousExecutionState)
    {
        case ApplicationExecutionState::Terminated: stateString = L"Terminated";
        case ApplicationExecutionState::ClosedByUser: stateString = L"Closed by user";
        case ApplicationExecutionState::NotRunning: stateString = L"Not running";
        case ApplicationExecutionState::Running: stateString = L"Running";
        case ApplicationExecutionState::Suspended: stateString = L"Suspended";
    }

    boost::wformat fmt = boost::wformat(L"App::OnLaunched - PreviousExecutionState: %s") % stateString;
    DEBUG_CONSOLE_TRACE_TO_FILE(fmt.str().c_str());

    // connect the shell to the app
    _shell->setApp(_app);

    // register for the rendering event and hook the panel...
    CompositionTarget::Rendering += ref new EventHandler<Object^>(this, &App::CompositionTargetRendering);

    // Place the frame in the current Window and ensure that it is active
    Window::Current->Content = p;

    p->setCommandObserver(std::dynamic_pointer_cast<view::icommand_observer>(_app));
    p->onLaunched();

    //Window::Current->Content = panel;
    Window::Current->Activate();

    // trace any baja exceptions being throw to a file
    setOnExceptionThrown([](const std::string& msg)
    {
        DEBUG_CONSOLE_TRACE_TO_FILE(strtowstr(msg).c_str());
    });
}

void App::CompositionTargetRendering(Object^ sender, Object^ args)
{
    _shell->render();
}

void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e)
{
    // place holder
}

void App::OnUnhandledException(Object^ sender, Windows::UI::Xaml::UnhandledExceptionEventArgs^ e)
{
    boost::wformat fmt = boost::wformat(L"!!UNHANDLED EXCEPTION!!: 0x%08x: %s") %
        e->Exception.Value %
        e->Message->Data();

    DEBUG_CONSOLE_TRACE_TO_FILE(fmt.str().c_str());
}
